package com.jun.admin.core.websocket;

import com.jun.admin.core.config.GetHttpSessionConfig;
import com.jun.admin.core.mapper.AdminWesocketLogMapper;
import com.jun.admin.core.model.AdminWesocketLog;

import jodd.util.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import tk.mybatis.mapper.entity.Example;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @author yuejun.li
 * @date 2024/10/19 15:51
 */
@Component
@Slf4j
//ServerEndpoint注解默认是多例的，每个连接都会创建一个新的实例
@ServerEndpoint(value = "/ws", configurator = GetHttpSessionConfig.class)
public class IndexWebSocket {

    private String userId;

    //存放websocket的集合
    private static Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();

    private static AdminWesocketLogMapper adminWesocketLogMapper;

    @Autowired
    public void setAdminWesocketLogMapper(AdminWesocketLogMapper adminWesocketLogMapper) {
        this.adminWesocketLogMapper = adminWesocketLogMapper;
    }

    /**
     * 建立连接
     * @param session
     */
    @OnOpen
    public void onOpen(Session session,EndpointConfig config) {
        Map<String, Object> userProperties = config.getUserProperties();
        this.userId = (String) userProperties.get(HttpSession.class.getName());
        onlineSessionClientMap.put(this.userId, session);
        log.info("【websocket消息】有新的连接, 总数:{}", onlineSessionClientMap.size());

        //向前端发送消息
        Example example = new Example(AdminWesocketLog.class);
        example.createCriteria()
                .andEqualTo(AdminWesocketLog.IS_PULL,0)
                .andEqualTo(AdminWesocketLog.USER_ID, this.userId);
        List<AdminWesocketLog> adminWesocketLogs = adminWesocketLogMapper.selectByExample(example);
        if(CollectionUtils.isNotEmpty(adminWesocketLogs)){
            for (AdminWesocketLog adminWesocketLog : adminWesocketLogs) {
                adminWesocketLog.setIsPull(1);
                adminWesocketLogMapper.updateByPrimaryKeySelective(adminWesocketLog);
                session.getAsyncRemote().sendText(adminWesocketLog.getMessage());
            }
        }
    }

    /**
     * 关闭连接
     */
    @OnClose
    public void onClose(Session session) {
        onlineSessionClientMap.remove(this.userId);
        log.info("【websocket消息】连接断开, 总数:{}", onlineSessionClientMap.size());
    }

    /**
     * 收到消息后的回调
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("【websocket消息】收到客户端发来的消息:{}", message);
    }

    /**
     * 发生错误时的回调
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.info("【websocket消息】收到客户端发来的错误消息:{}", error.getMessage());
    }

    @Scheduled(cron = "0/5 * * * * ?")
    private void sendMessage(){
        if(this.userId == null){
            return;
        }
        Session session = onlineSessionClientMap.get(this.userId);
        //向前端发送消息
        Example example = new Example(AdminWesocketLog.class);
        example.createCriteria()
                .andEqualTo(AdminWesocketLog.IS_PULL,0)
                .andEqualTo(AdminWesocketLog.USER_ID, this.userId);
        List<AdminWesocketLog> adminWesocketLogs = adminWesocketLogMapper.selectByExample(example);
        if(CollectionUtils.isNotEmpty(adminWesocketLogs)){
            for (AdminWesocketLog adminWesocketLog : adminWesocketLogs) {
                adminWesocketLog.setIsPull(1);
                adminWesocketLogMapper.updateByPrimaryKeySelective(adminWesocketLog);
                session.getAsyncRemote().sendText(adminWesocketLog.getMessage());
            }
        }
    }
}
